package com.five.service.impl;


import com.five.api.AuthorServiceAPI;
import com.five.api.ReaderServiceAPI;
import com.five.dto.RegisterDto;
import com.five.exception.BusinessException;
import com.five.pojo.Author;
import com.five.pojo.Reader;
import com.five.service.RegisterService;
import com.five.util.StrUtils;
import com.five.util.VerifyCodeUtils;
import io.seata.spring.annotation.GlobalTransactional;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.DigestUtils;
import javax.mail.MessagingException;
import javax.mail.internet.MimeMessage;
import java.time.LocalDateTime;
import java.util.Date;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

@Service
public class RegisterServiceImpl implements RegisterService {
    //定义手机号的正则表达式
    private static final String PHONE_REGEX = "^1[3-9]\\d{9}$";
    //编译正则表达式模式
    private static final Pattern PHONE_PATTERN = Pattern.compile(PHONE_REGEX);
    // 定义邮箱的正则表达式
    private static final String EMAIL_REGEX = "^[A-Za-z0-9+_.-]+@[A-Za-z0-9.-]+$";
    // 编译正则表达式
    private static final Pattern EMAIL_PATTERN = Pattern.compile(EMAIL_REGEX);

    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private JavaMailSender javaMailSender;
    @Autowired
    private AuthorServiceAPI authorServiceAPI;
    @Autowired
    private ReaderServiceAPI readerServiceAPI;

    /**
     * 获取验证码图片的base64编码
     * @param code
     * @return
     */
    @Override
    public String getBase64Image(String code) {
        if(code == null || code.isEmpty()){
                throw new BusinessException("验证码键值不能为空");
        }
        String verifyCode = StrUtils.getRandomString(4);
        System.out.println("图形验证码："+verifyCode);
        redisTemplate.opsForValue().set(code, verifyCode,2, TimeUnit.MINUTES);
        return VerifyCodeUtils.VerifyCode(100,40,verifyCode);
    }

    /**
     * 发送手机验证码
     */
    @Override
    public String sendPhoneVerifyCode(String phoneNumber) {
        Matcher matcher = PHONE_PATTERN.matcher(phoneNumber);
        if (!matcher.matches()) {
            throw new BusinessException("手机号格式不正确");
        }
        String key = "sendPhoneVerifyCode:" + phoneNumber;
        System.out.println("手机验证码键值:"+key);
        String code;
        String phoneVerifyCode = (String) redisTemplate.opsForValue().get(key);
        if(phoneVerifyCode != null && !phoneVerifyCode.isEmpty()){
            String saveTime = phoneVerifyCode.split(":")[1];
            long time = System.currentTimeMillis() - Long.parseLong(saveTime);
            if(time < 1*60*1000){
                throw new BusinessException("验证码发送频繁，请稍后再试");
            }else{
                //刷新过期时间
                code = phoneVerifyCode.split(":")[0];
            }
        }else{
            code = StrUtils.getRandomString(4);
        }
        redisTemplate.opsForValue().set(key, code + ":" + System.currentTimeMillis(), 5*60*1000, TimeUnit.MILLISECONDS);
        //发送验证码
        System.out.println("发送手机验证码到手机号: " + phoneNumber + " 验证码为: " + code);
        return key;
    }

    /**
     * 验证图片验证码
     * @param inputCode
     * @param key
     * @return
     */
    @Override
    public void verifyImageVerifyCode(String inputCode, String key) {
        if(inputCode == null || inputCode.isEmpty()){
            throw new BusinessException("验证码不能为空");
        }
        if(key == null || key.isEmpty()){
            throw new RuntimeException("验证码键值不能为空");
        }
        String verifyCode = (String) redisTemplate.opsForValue().get(key);
        if(verifyCode == null || verifyCode.isEmpty()){
            throw new BusinessException("图片验证码已过期，请重新获取验证码");
        }
        if(!verifyCode.equals(inputCode)){
            throw new BusinessException("图片验证码错误");
        }
    }

    /**
     *  验证手机验证码
     * @param key
     * @param inputCode
     * @return
     */
    @Override
    public void verifyPhoneVerifyCode(String key,String inputCode) {
        if(key == null || key.isEmpty()){
            throw new RuntimeException("验证码键值不能为空");
        }
        if(inputCode == null || inputCode.isEmpty()){
            throw new BusinessException("验证码不能为空");
        }
        String phoneVerifyCode = (String) redisTemplate.opsForValue().get(key);
        if(phoneVerifyCode == null || phoneVerifyCode.isEmpty()){
            throw new BusinessException("手机验证码已过期");
        }
        if(!phoneVerifyCode.split(":")[0].equals(inputCode)){
            throw new BusinessException("手机验证码错误");
        }
    }

    /**
     * 手机号注册用户
     * @param registerDto
     */
    @Override
    @Transactional
    @GlobalTransactional
    public void registerPhone(RegisterDto registerDto) {
        String phone = registerDto.getPhone();
        String password = registerDto.getPassword();
        String confirmPassword = registerDto.getConfirmPassword();
        String imageCodeKey = registerDto.getImageCodeKey();
        String phoneCodeKey = registerDto.getPhoneCodeKey();
        Integer type = registerDto.getType();
        //1.非空校验
        if(phone == null || phone.toString().isEmpty()){
            throw new BusinessException("手机号不能为空");
        }
        if(password == null || password.toString().isEmpty()){
            throw new BusinessException("密码不能为空");
        }
        if(confirmPassword == null || confirmPassword.toString().isEmpty()){
            throw new BusinessException("确认密码不能为空");
        }
        //2.手机号格式校验
        Matcher matcher = PHONE_PATTERN.matcher(phone.toString());
        if (!matcher.matches()) {
            throw new BusinessException("手机号格式不正确");
        }
        //3.密码与确认密码是否一致校验
        if(!password.toString().equals(confirmPassword.toString())) {
            throw new BusinessException("密码与确认密码不一致");
        }

        if(type == 1){
            //作者注册
            //手机号是否已注册校验
            Author author = (Author) authorServiceAPI.queryByPhone(phone.toString()).getData();
            String salt = UUID.randomUUID().toString();
            String md5Password = DigestUtils.md5DigestAsHex((salt + password).getBytes());
            if(author!= null){
                throw new BusinessException("手机号已注册");
            }else{
                author = new Author();
                //作者不存在，新增作者信息
                BeanUtils.copyProperties(registerDto,author);
                author.setSalt(salt);
                author.setPassword(md5Password);
                author.setCreateTime(new Date());
                author.setStatus(1);
                author.setUpdateTime(new Date());
                authorServiceAPI.insertAuthor(author);
            }
        }else if(type == 2){
            //读者注册
            //手机号是否已注册校验
            Reader reader = (Reader) readerServiceAPI.queryByPhone(phone.toString()).getData();
            String salt = UUID.randomUUID().toString();
            String md5Password = DigestUtils.md5DigestAsHex((salt + password).getBytes());
            if(reader!= null){
                throw new BusinessException("手机号已注册");
            }else{
                reader = new Reader();
                //读者不存在，新增读者信息
                BeanUtils.copyProperties(registerDto,reader);
                reader.setSalt(salt);
                reader.setPassword(md5Password);
                reader.setCreate_time(LocalDateTime.now());
                reader.setStatus(1);
                reader.setUpdate_time(LocalDateTime.now());
                readerServiceAPI.insertReader(reader);
            }
        }
        //5. 注册成功，删除验证码
        redisTemplate.delete(imageCodeKey);
        redisTemplate.delete(phoneCodeKey);
    }

    /**
     * 发送邮箱验证码
     * @param email
     * @return
     */
    @Override
    public String sendEmailVerifyCode(String email) throws MessagingException {
        Matcher matcher = EMAIL_PATTERN.matcher(email);
        if (!matcher.matches()) {
            throw new BusinessException("邮箱格式不正确");
        }
        String key = "sendEmailVerifyCode:" + email;
        String code;
        String emailVerifyCode = (String) redisTemplate.opsForValue().get(key);
        if(emailVerifyCode != null && !emailVerifyCode.isEmpty()){
            String saveTime = emailVerifyCode.split(":")[1];
            long time = System.currentTimeMillis() - Long.parseLong(saveTime);
            if(time < 1*60*1000){
                throw new BusinessException("验证码发送频繁，请稍后再试");
            }else{
                //刷新过期时间
                code = emailVerifyCode.split(":")[0];
            }
        }else{
            code = StrUtils.getRandomString(4);
        }
        redisTemplate.opsForValue().set(key, code + ":" + System.currentTimeMillis(), 5*60*1000, TimeUnit.MILLISECONDS);
        //发送验证码
        System.out.println("send email verify code to " + email + " code is " + code);
        //创建复杂邮件对象
        MimeMessage mimeMessage = javaMailSender.createMimeMessage();
        //发送复杂邮件的工具类
        MimeMessageHelper mailMessage = new MimeMessageHelper(mimeMessage,true,"utf-8");
        //设置发送人
        mailMessage.setFrom("3281276718@qq.com");
        //邮件主题
        mailMessage.setSubject("邮箱注册验证码");
        //邮件内容
        StringBuilder emailContent = new StringBuilder();
        emailContent.append("尊敬的用户，您好！\n\n");
        emailContent.append("感谢您使用我们的服务。\n");
        emailContent.append("您正在进行邮箱验证，以下是您的验证码：\n\n");
        emailContent.append("<h2 style='color:#4CAF50;'>验证码: ").append(code).append("</h2>\n\n");
        emailContent.append("请在接下来的5分钟内，将此验证码输入到验证页面中完成验证。\n");
        emailContent.append("如果您没有进行此操作，请忽略此邮件。\n\n");
        emailContent.append("祝您使用愉快！\n");
        mailMessage.setText(emailContent.toString(),true);
        //收件人
        mailMessage.setTo(email);

        javaMailSender.send(mimeMessage);
        return key;
    }

    /**
     * 邮箱注册用户
     * @param registerDto
     */
    @Override
    @Transactional
    @GlobalTransactional
    public void registerEmail(RegisterDto registerDto) {
        String email = registerDto.getEmail();
        String password = registerDto.getPassword();
        String confirmPassword = registerDto.getConfirmPassword();
        String imageCodeKey = registerDto.getImageCodeKey();
        String phoneCodeKey = registerDto.getPhoneCodeKey();
        Integer type = registerDto.getType();
        //1.非空校验
        if(email == null || email.isEmpty()){
            throw new BusinessException("邮箱不能为空");
        }
        if(password == null || password.toString().isEmpty()){
            throw new BusinessException("密码不能为空");
        }
        if(confirmPassword == null || confirmPassword.toString().isEmpty()){
            throw new BusinessException("确认密码不能为空");
        }
        //2.手机号格式校验
        Matcher matcher = EMAIL_PATTERN.matcher(email);
        if (!matcher.matches()) {
            throw new BusinessException("邮箱格式不正确");
        }
        //3.密码与确认密码是否一致校验
        if(!password.toString().equals(confirmPassword.toString())) {
            throw new BusinessException("密码与确认密码不一致");
        }

        if(type == 1){
            //作者注册
            //手机号是否已注册校验
            Author author = (Author) authorServiceAPI.queryByEmail(email).getData();
            String salt = UUID.randomUUID().toString();
            String md5Password = DigestUtils.md5DigestAsHex((salt + password).getBytes());
            if(author!= null){
                throw new BusinessException("邮箱已注册");
            }else{
                author = new Author();
                //作者不存在，新增作者信息
                BeanUtils.copyProperties(registerDto,author);
                author.setSalt(salt);
                author.setPassword(md5Password);
                author.setCreateTime(new Date());
                author.setStatus(1);
                author.setUpdateTime(new Date());
                authorServiceAPI.insertAuthor(author);
            }
        }else if(type == 2){
            //读者注册
            //手机号是否已注册校验
            Reader reader = (Reader) readerServiceAPI.queryByEmail(email.toString()).getData();
            String salt = UUID.randomUUID().toString();
            String md5Password = DigestUtils.md5DigestAsHex((salt + password).getBytes());
            if(reader!= null){
                throw new BusinessException("邮箱已注册");
            }else{
                reader = new Reader();
                //读者不存在，新增读者信息
                BeanUtils.copyProperties(registerDto,reader);
                reader.setSalt(salt);
                reader.setPassword(md5Password);
                reader.setCreate_time(LocalDateTime.now());
                reader.setStatus(1);
                reader.setUpdate_time(LocalDateTime.now());
                readerServiceAPI.insertReader(reader);
            }
        }
        //5. 注册成功，删除验证码
        redisTemplate.delete(imageCodeKey);
        redisTemplate.delete(phoneCodeKey);
    }

    /**
     * 验证邮箱验证码
     * @param key
     * @param inputCode
     */
    @Override
    public void verifyEmailVerifyCode(String key, String inputCode) {
        if(key == null || key.isEmpty()){
            throw new RuntimeException("验证码键值不能为空");
        }
        if(inputCode == null || inputCode.isEmpty()){
            throw new BusinessException("验证码不能为空");
        }
        String emailVerifyCode = (String) redisTemplate.opsForValue().get(key);
        if(emailVerifyCode == null || emailVerifyCode.isEmpty()){
            throw new BusinessException("邮箱验证码已过期");
        }
        if(!emailVerifyCode.split(":")[0].equals(inputCode)){
            throw new BusinessException("输入的邮箱验证码错误");
        }
    }
}